package com.bckj.fastboot.flow.process.expression;

import com.bckj.fastboot.core.lang.exception.BusinessException;
import com.bckj.fastboot.core.util.ExecutionContext;
import jakarta.el.*;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.lang.reflect.Method;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class CustomExpressionProcessor implements ExpressionProcessor, ApplicationContextAware {

    // 匹配静态方法调用表达式，支持参数
    private static final Pattern STATIC_METHOD_PATTERN =
            Pattern.compile("\\$\\{T\\(([\\w.]+)\\)\\.(\\w+)\\(([^)]*)\\)\\}");

    private final ExpressionFactory expressionFactory = ExpressionFactory.newInstance();
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public Object evaluate(String expression, ExecutionContext context) {
        try {
            // 处理静态方法调用表达式
            Matcher matcher = STATIC_METHOD_PATTERN.matcher(expression);
            if (matcher.matches()) {
                String className = matcher.group(1);
                String methodName = matcher.group(2);
                String paramsStr = matcher.group(3);
                return evaluateStaticMethod(className, methodName, paramsStr, context);
            }
            // 处理普通表达式
           return evaluateExpression(expression, context);
        } catch (Exception e) {
            throw new BusinessException("Failed to evaluate expression: " + expression);
        }
    }

    private Object evaluateStaticMethod(String className, String methodName,
                                        String paramsStr, ExecutionContext context) throws Exception {

        // 解析参数列表
        String[] paramExpressions = paramsStr.isEmpty() ? new String[0] : paramsStr.split("\\s*,\\s*");
        Object[] args = new Object[paramExpressions.length];
        Class<?>[] paramTypes = new Class[paramExpressions.length];
        // 评估每个参数表达式
        for (int i = 0; i < paramExpressions.length; i++) {
            args[i] = evaluateParamExpression(paramExpressions[i], context);
            paramTypes[i] = args[i] != null ? args[i].getClass() : Object.class;
        }

        // 通过反射调用静态方法
        Class<?> clazz = Class.forName(className);
        Method method = clazz.getDeclaredMethod(methodName, paramTypes);
        return method.invoke(null, args);
    }

    private Object evaluateParamExpression(String expr, ExecutionContext context) throws Exception {
        // 如果是简单变量引用（如 "varName"）
        if (context.containsKey(expr)) {
            return context.get(expr);
        }

        // 如果是复杂表达式（如 "varName + 1"），使用完整表达式评估
        return evaluateExpression("${" + expr + "}", context);
    }

    private Object evaluateExpression(String expression, ExecutionContext context) throws Exception {
        // 处理普通表达式
        ELContext elContext = createELContext(context);
        ValueExpression ve = expressionFactory.createValueExpression(elContext, expression, Object.class);
        return ve.getValue(elContext);
    }

    private ELContext createELContext(ExecutionContext context) {
        return new ELContext() {
            private final CompositeELResolver resolver = new CompositeELResolver();
            {
                // 添加Bean解析器
                resolver.add(new BeanELResolver());
                // 添加自定义Bean注册表解析器
                resolver.add(new CustomBeanELResolver(applicationContext));
                // 添加变量解析器
                resolver.add(new VariableELResolver(context));
            }

            @Override
            public ELResolver getELResolver() {
                return resolver;
            }

            @Override
            public FunctionMapper getFunctionMapper() {
                return null;
            }

            @Override
            public VariableMapper getVariableMapper() {
                return null;
            }
        };
    }

    static class CustomBeanELResolver extends ELResolver {

        private final ApplicationContext applicationContext;

        public CustomBeanELResolver(ApplicationContext applicationContext) {
            this.applicationContext = applicationContext;
        }

        @Override
        public Object getValue(ELContext context, Object base, Object property) {
            if (base == null && property != null) {
                String beanName = property.toString();
                if (applicationContext.containsBean(beanName)) {
                    context.setPropertyResolved(true);
                    return applicationContext.getBean(beanName);
                }
            }
            return null;
        }

        @Override
        public Class<?> getType(ELContext context, Object base, Object property) {
            return null;
        }

        @Override
        public void setValue(ELContext context, Object base, Object property, Object value) {

        }

        @Override
        public boolean isReadOnly(ELContext context, Object base, Object property) {
            return false;
        }

        @Override
        public Class<?> getCommonPropertyType(ELContext context, Object base) {
            return null;
        }
    }

    static class VariableELResolver extends ELResolver {
        private final ExecutionContext context;

        public VariableELResolver(ExecutionContext context) {
            this.context = context;
        }

        @Override
        public Object getValue(ELContext elContext, Object base, Object property) {
            if (base == null && property != null) {
                String varName = property.toString();
                if (context.containsKey(varName)) {
                    elContext.setPropertyResolved(true);
                    return context.get(varName);
                }
            }
            return null;
        }

        @Override
        public Class<?> getType(ELContext context, Object base, Object property) {
            return null;
        }

        @Override
        public void setValue(ELContext context, Object base, Object property, Object value) {

        }

        @Override
        public boolean isReadOnly(ELContext context, Object base, Object property) {
            return false;
        }

        @Override
        public Class<?> getCommonPropertyType(ELContext context, Object base) {
            return null;
        }
    }
}
